package env

import (
	"os"
	"strconv"
	"strings"
	"time"
)

var nameFix func(name string) string

func fixKey(key string) string {
	if key != "" && nameFix != nil {
		key = nameFix(key)
	}
	return key
}

func getEnv(key string) string {
	if key = fixKey(key); key == "" {
		return ""
	}
	return os.Getenv(key)
}

func NameFix(nameFixFunc func(name string) string) {
	nameFix = nameFixFunc
}

func SetEnv(key string, value string) {
	if key = fixKey(key); key == "" {
		return
	}
	if value == "" {
		_ = os.Unsetenv(key)
	} else {
		_ = os.Setenv(key, value)
	}
}

func GetString(key string, defaultValue ...string) string {
	if s := getEnv(key); s != "" {
		return s
	}
	if len(defaultValue) > 0 {
		for _, v := range defaultValue {
			if v != "" {
				return v
			}
		}
	}
	return ""
}

func GetInt(key string, defaultValue ...int64) int64 {
	if s := getEnv(key); s != "" {
		if v, err := strconv.ParseInt(s, 10, 64); err == nil {
			return v
		}
	}

	if len(defaultValue) > 0 {
		for _, v := range defaultValue {
			if v != 0 {
				return v
			}
		}
	}
	return 0
}

func GetFloat(key string, defaultValue ...float64) float64 {
	if s := getEnv(key); s != "" {
		if v, err := strconv.ParseFloat(s, 64); err == nil {
			return v
		}
	}
	if len(defaultValue) > 0 {
		for _, v := range defaultValue {
			if v != 0 {
				return v
			}
		}
	}
	return 0
}

func GetBool(key string, defaultValue ...bool) bool {
	if s := getEnv(key); s != "" {
		if v, err := strconv.ParseBool(s); err == nil {
			return v
		}
	}
	if len(defaultValue) > 0 {
		return defaultValue[0]
	}
	return false
}

func IsTrue(key string) bool {
	if s := getEnv(key); s != "" {
		if v, err := strconv.ParseBool(s); err == nil {
			return v
		}
	}
	return false
}

func IsFalse(key string) bool {
	if s := getEnv(key); s != "" {
		if v, err := strconv.ParseBool(s); err == nil {
			return !v
		}
	}
	return false
}

func GetDuration(key string, defaultValue ...time.Duration) time.Duration {
	if s := getEnv(key); s != "" {
		if v, err := time.ParseDuration(s); err == nil {
			return v
		}
	}
	if len(defaultValue) > 0 {
		for _, v := range defaultValue {
			if v != 0 {
				return v
			}
		}
	}
	return 0
}

func GetStrings(key string, defaultValue ...string) []string {
	if s := getEnv(key); s != "" {
		return strings.Split(s, ",")
	}
	return defaultValue
}

func GetInts(key string, defaultValue ...int64) []int64 {
	if s := getEnv(key); s != "" {
		ss := strings.Split(s, ",")
		var is []int64
		for _, x := range ss {
			if i, err := strconv.ParseInt(x, 10, 64); err == nil {
				is = append(is, i)
			}
		}
		if len(is) > 0 {
			return is
		}
	}
	return defaultValue
}

func GetFloats(key string, defaultValue ...float64) []float64 {
	if s := getEnv(key); s != "" {
		ss := strings.Split(s, ",")
		var fs []float64
		for _, x := range ss {
			if f, err := strconv.ParseFloat(x, 64); err == nil {
				fs = append(fs, f)
			}
		}
		if len(fs) > 0 {
			return fs
		}
	}
	return defaultValue
}

func GetBooleans(key string, defaultValue ...bool) []bool {
	if s := getEnv(key); s != "" {
		ss := strings.Split(s, ",")
		var fs []bool
		for _, x := range ss {
			if f, err := strconv.ParseBool(x); err == nil {
				fs = append(fs, f)
			}
		}
		if len(fs) > 0 {
			return fs
		}
	}
	return defaultValue
}

func GetMode() string {
	return getEnv("RunMode")
}

func IsDEVMode() bool {
	return strings.ToLower(getEnv("RunMode")) == "dev"
}
